using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using Comteck.Winforms.Controls;
using Comteck.Winforms.Validations;
using DevExpress.Utils.MVVM;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.DXErrorProvider;

namespace Comteck.Winforms {
  /// <summary>
  /// Mvvm模式相关扩展方法
  /// </summary>
  public static class MVVMContextExtensions {

      /// <summary>
      /// 使用Mvvm绑定界面
      /// </summary>
      /// <typeparam name="TEntity"></typeparam>
      /// <param name="context">MVVMContext</param>
      /// <param name="entity">mvvm模型</param>
      /// <param name="validate">验证控件</param>
      /// <param name="ignoreCase">是否忽略控件的大小写</param>
      /// <param name="prefix">控件前缀</param>
      /// <returns></returns>
      public static MVVMContext BindForm<TEntity>(this MVVMContext context, TEntity entity, DXValidationProvider validate = null, bool ignoreCase = true, string prefix = "ck") where TEntity : class, new() {
      // 绑定ViewModel
      context.SetViewModel(entity.GetType(), entity);

      // 遍历所有的string类型的字符串
      var propertyArray = typeof(TEntity).GetTypeInfo().GetProperties(BindingFlags.GetProperty
        | BindingFlags.Public | BindingFlags.Instance);

      if (propertyArray == null || propertyArray.Count() == 0) {
        return context;
      }

      // 查找所有的验证模型
      if (validate != null) {
        validate.ValidationMode = ValidationMode.Default; // 验证类型
      }
      var rules = DataAnnotationHelper.GetValidationRules(entity);

      // mvvmcontext的容器
      var controlForm = context.ContainerControl;

      // 循环所有属性,去
      foreach (var property in propertyArray) {
        // 根据属性去容器中查询控件
        var control = controlForm.FindControlLoop($"{prefix}{property.Name}", ignoreCase);

        if (control == null) {
          continue;
        }

        SetBindingByControl(context, control, property.Name);

        if (validate != null) {
          // 查找验证规则
          var mvcRuleList = rules.Where(x => x.Field == property.Name).OrderBy(x => x.Order).ThenBy(x => (int)x.ValidationType).AsEnumerable();

          // 查找特性并且绑定验证属性
          SetValidationRule(validate, control, mvcRuleList);
        }
      }

      return context;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="control"></param>
    /// <param name="propertyName"></param>
    private static void SetBindingByControl(MVVMContext context, Control control, string propertyName) {

      if (control is TextBoxBase textBox) {
        // 文本框,包括 TextBox,RickTextBox,MaskedTextBox
        context.SetBinding(textBox, c => c.Text, propertyName);
      } else if (control is NumericUpDown numericUpDown) {
        // 数字文本框
        context.SetBinding(numericUpDown, c => c.Value, propertyName);
      } else if (control is DateTimePicker dateTimePicker) {
        // 日期选择框
        context.SetBinding(dateTimePicker, c => c.Value, propertyName);
      } else if (control is CheckBox checkBox) {
        // 复选框
        context.SetBinding(checkBox, c => c.CheckState, propertyName);
      } else if (control is System.Windows.Forms.ComboBox comboBox) {
        // 下拉框
        context.SetBinding(comboBox, c => c.SelectedValue, propertyName);
      } else if (control is RadioButton radioButton) {
        // 下拉框
        context.SetBinding(radioButton, c => c.Checked, propertyName);

        // ---------------- 以下是针对 DEV 控件的
      } else if (control is LookUpEdit lookUpEdit) {
        context.SetBinding(lookUpEdit, c => c.EditValue, propertyName);
      } else if (control is TreeListLookUpEdit treeListLookUpEdit) {
        context.SetBinding(treeListLookUpEdit, c => c.EditValue, propertyName);
      } else if (control is ComboBoxEdit comboBoxEdit) {
        context.SetBinding(comboBoxEdit, c => c.EditValue, propertyName);
      } else if (control is DateEdit dateEdit) {
        //context.SetBinding(dateEdit, c => c.DateTime, propertyName); // DateTime不支持null，只支持最小值DateTime.MinValue
        context.SetBinding(dateEdit, c => c.EditValue, propertyName); // EditValue支持null
      } else if (control is TimeEdit timeEdit) {
        context.SetBinding(timeEdit, c => c.Time, propertyName);
      } else if (control is RadioGroup radioGroup) {
        context.SetBinding(radioGroup, c => c.SelectedIndex, propertyName);
      } else if (control is ColorEdit) {
        // TODO ColorEdit尚未实现MVVM
      } else if (control is MyCheckEdit myCheckEdit) {
        context.SetBinding(myCheckEdit, c => c.EditValue, propertyName);
      } else if (control is CheckEdit checkEdit) {
        context.SetBinding(checkEdit, c => c.EditValue, propertyName);
      } else if (control is CheckedComboBoxEdit checkedComboBoxEdit) {
        // MVVM赋值后，显示的是Value，不是Name,还是需要再次手工执行this.ckControl.SetEditValue(entityModel.Ids)
        context.SetBinding(checkedComboBoxEdit, c => c.EditValue, propertyName);
      } else if (control is MemoExEdit memoExEdit) {
        context.SetBinding(memoExEdit, c => c.EditValue, propertyName);
      } else if (control is MemoEdit memoEdit) {
        context.SetBinding(memoEdit, c => c.EditValue, propertyName);
      } else if (control is SpinEdit spinEdit) {
        context.SetBinding(spinEdit, c => c.EditValue, propertyName);
      } else if (control is TextEdit textEdit) {
        context.SetBinding(textEdit, c => c.EditValue, propertyName);
      } else if (control is ToggleSwitch toggleSwitch) {
        context.SetBinding(toggleSwitch, c => c.EditValue, propertyName);
      }
    }

    /// <summary>
    /// 绑定验证控件,这里暂时只做三个常用的，包括
    /// Maxlength,Stringlength,Required
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="validate">MVVMContext</param>
    /// <param name="container">查找的容器</param>
    /// <param name="entity">mvvm模型</param>
    /// <param name="ignoreCase">是否忽略控件的大小写</param>
    /// <param name="prefix">控件前缀</param>
    /// <returns></returns>
    public static void BindValidator<TEntity>(this DXValidationProvider validate, Control container, TEntity entity, bool ignoreCase = true, string prefix = "ck") where TEntity : class, new() {
      // 绑定ViewModel
      validate.ValidationMode = ValidationMode.Default; // 验证类型

      // 遍历所有的string类型的字符串
      var propertyArray = typeof(TEntity).GetTypeInfo().GetProperties(BindingFlags.GetProperty
        | BindingFlags.Public | BindingFlags.Instance);

      if (propertyArray == null || propertyArray.Count() == 0) {
        return;
      }

      // 查找所有的验证模型
      var rules = DataAnnotationHelper.GetValidationRules(entity);

      // 循环所有属性,去
      foreach (var property in propertyArray) {
        // 根据属性去容器中查询控件
        var control = container.FindControlLoop($"{prefix}{property.Name}", ignoreCase);

        if (control == null || control.Visible == false) {
          continue;
        }

        // 查找验证规则
        var mvcRuleList = rules.Where(x => x.Field == property.Name).OrderBy(x => x.Order).ThenBy(x => (int)x.ValidationType).AsEnumerable();

        // 查找特性并且绑定验证属性
        SetValidationRule(validate, control, mvcRuleList);
      }
    }


    /// <summary>
    /// 添加验证规则
    /// </summary>
    /// <param name="validate"></param>
    /// <param name="control"></param>
    /// <param name="mvcRuleList">mvcRuleList</param>
    private static void SetValidationRule(DXValidationProvider validate, Control control, IEnumerable<MvcValidationRule> mvcRuleList) {
      var rule = ValidationRuleHelper.GetRule(mvcRuleList);

      if (rule != null) {
        validate.SetValidationRule(control, rule);
        validate.SetIconAlignment(control, ErrorIconAlignment.MiddleRight);
      }
    }

  }
}
